﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Wiyan.Code.PowerMSNRobotLibrary.SDK;
using System.Diagnostics;
using Wiyan.Code.PowerMSNRobotLibrary.Commands;
using Wiyan.Code.PowerMSNRobotLibrary.Utility;
using XihSolutions.DotMSN;

namespace Wiyan.Code.PowerMSNRobotLibrary.Manager
{
    public class RobotManager
    {
        public delegate void ReplyMessageDelay(object sender, string message);
        private ReplyMessageDelay _messageASyncSender = null;
        private static RobotManager _robotManager = null;
        private Dictionary<string, ICommandProvider> _filters = new Dictionary<string, ICommandProvider>();
        private ICommandProvider _currentCommandProvider = null;
        private List<string> _acl = new List<string>();
        private Messenger _messenger = null;
        private Contact _currentContact = null;

        public Contact CurrentContact
        {
            get { return _currentContact; }
            set { _currentContact = value; }
        }

        public Messenger Messenger
        {
            get { return _messenger; }
            set { _messenger = value; }
        }

        public ReplyMessageDelay MessageASyncSender
        {
            get { return _messageASyncSender; }
            set { _messageASyncSender = value; }
        }


        public ICommandProvider[] SupporttedCommands
        {
            get { return _filters.Values.ToArray(); }
        }
        
        public List<string> Acl
        {
            get { return _acl; }
        }

        private RobotManager()
        {
            CommandLineHelper.WorkerProcessExitHandler = this.CommandProcessExitHandler;
        }

        public static RobotManager GetInstance()
        {
            if (_robotManager == null)
            {
                _robotManager = new RobotManager();
            }

            return _robotManager;
        }

        public void RegisterAdmin(string mail)
        {
            _acl.Add(mail.Trim().ToLower());
        }

        public bool IsApproved(string mail)
        {
            return _acl.Contains(mail.Trim().ToLower());
        }

        public void RegisterFilter(ICommandProvider commandProvider)
        {
            Debug.Assert(commandProvider != null);

            if (_filters.ContainsKey(commandProvider.Name) == true)
            {
                throw new Exception(string.Format("Already register filter for filter: {0}", commandProvider.Name));
            }

            _filters.Add(commandProvider.Name, commandProvider);
        }

        private void CommandProcessExitHandler(object sender, System.EventArgs e)
        {
            if (_currentCommandProvider != null)
            {
                ExclusiveComanCommandProvider lastExclusiveCommandProvider = _currentCommandProvider as ExclusiveComanCommandProvider;

                if (lastExclusiveCommandProvider != null)
                {
                    lastExclusiveCommandProvider.Close();
                }
            }
        }
 
        /// <summary>
        /// Recieved text message
        /// </summary>
        /// <param name="message"></param>
        /// <returns>Should continue?, true: yes, false: no</returns>
        public bool ApplyFilter(int contactCode, string message, ref string replyMessage)
        {
            string[] commands = message.Split(' ');
            string command = commands[0].ToLower();
            ErrorCode errorCode = ErrorCode.Error;
            ExclusiveComanCommandProvider lastExclusiveCommandProvider = _currentCommandProvider as ExclusiveComanCommandProvider;

            // Run sub command if last command is exclusive
            if (_currentCommandProvider != null && lastExclusiveCommandProvider != null && lastExclusiveCommandProvider.Status == CommandStatus.Running)
            {
                ExclusiveComanCommandProvider provider = _currentCommandProvider as ExclusiveComanCommandProvider;
                if (string.Compare(command, provider.EndCommand, true) == 0)
                {
                    errorCode = provider.Close();
                    replyMessage = ErrorInformation.GetDetailError(errorCode);
                }
                else
                {
                    StringBuilder sb = new StringBuilder();
                    try
                    {
                        errorCode = provider.ProcessSubCommand(message);
                    }
                    catch (Exception e)
                    {
                        replyMessage = e.Message;
                        return true;
                    }

                    sb.AppendLine("Process sub command: " + message + "\t" + ErrorInformation.GetDetailError(errorCode));
                    sb.AppendLine("Press " + lastExclusiveCommandProvider.EndCommand + " to exit current command session");
                    replyMessage = sb.ToString();
                }

                return true;
            }
            else if (_filters.ContainsKey(command) == true)
            {
                // Run comman command provider
                ICommandProvider commandProvider = _filters[command] as ICommandProvider;
                ExclusiveComanCommandProvider exclusiveCommandProvider = commandProvider as ExclusiveComanCommandProvider;

                if (_currentCommandProvider != null && lastExclusiveCommandProvider != null && lastExclusiveCommandProvider.Status == CommandStatus.Running)
                {
                    replyMessage = string.Format("Robot is busy for last exclusive command, please type {0} to quit", lastExclusiveCommandProvider.EndCommand);
                    return true;
                }
                else if (exclusiveCommandProvider != null)
                {
                    // call start for exclusive command
                    string reallyCommand = message.Substring(command.Length, message.Length - command.Length).Trim();
                    string[] reallyCommands = reallyCommand.Split(' ');
                    string defaultCommand = string.Empty;
                    string defaultArgs = string.Empty;

                    if (reallyCommands.Length > 0 && 
                        (string.IsNullOrEmpty(reallyCommands[0]) == false))
                    {
                        defaultCommand = reallyCommands[0];
                    }

                    if (reallyCommands.Length > 1)
                    {
                        defaultArgs = reallyCommand.Substring(reallyCommands[0].Length, reallyCommand.Length - reallyCommands[0].Length).Trim();
                    }

                    try
                    {
                        errorCode = exclusiveCommandProvider.Start(new object[] { defaultCommand, defaultArgs });
                    }
                    catch (Exception e)
                    {
                        replyMessage = e.Message;
                        return true;
                    }
 
                    StringBuilder sb = new StringBuilder();   
                    sb.AppendLine("Process command: " + defaultCommand + "\t" + ErrorInformation.GetDetailError(errorCode));
                    sb.AppendLine("Press " + exclusiveCommandProvider.EndCommand + " to exit current command session");
                    replyMessage = sb.ToString();
                }
                else
                {
                    ICommandResultBase result = _filters[command].Run(commands);
                    replyMessage = result.ReplyMessage;
                }

                _currentCommandProvider = commandProvider;
                return true;
            }

            return false;
        }
    }
}
